﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DiffPlex.DiffBuilder.Model;
using System.Drawing.Drawing2D;

namespace DevelopAssistant.AddIn.Diffplex
{
    public partial class NRichTextBoxControl : Panel
    {
        public ScrollEventPlasHandler ScrollChanged = null;

        public new string Text
        {
            get { return this.richTextBox.Text; }
            set
            {
                this.richTextBox.Text = value;
                if (viewTextBox != null)
                    viewTextBox.ResetScrollPos();
            }
        }

        public EditTextBox richTextBox = new EditTextBox();
        public ViewTextBox viewTextBox = new ViewTextBox();

        public NRichTextBoxControl()
        {
            InitializeComponent();
            InitializeControls();
        }

        private void InitializeControls()
        {
            this.Padding = new Padding(4, 4, 4, 4);
            this.BackColor = Color.White;
            this.richTextBox.Multiline = true;
            this.richTextBox.ScrollBars = ScrollBars.Vertical;
            this.richTextBox.Dock = DockStyle.Fill;
            this.richTextBox.BorderStyle = BorderStyle.None;
            this.Controls.Add(this.richTextBox);

            this.viewTextBox.Multiline = true;
            this.viewTextBox.ScrollBars = ScrollBars.Vertical;
            this.viewTextBox.Dock = DockStyle.Fill;
            this.viewTextBox.BorderStyle = BorderStyle.None;
            this.Controls.Add(this.viewTextBox);

            this.viewTextBox.ncontrol = this;

        }

        public void SetRenderModel(DiffPaneModel model)
        {            
            Font font = this.richTextBox.Font;            
            if (model != null)
            {
                this.richTextBox.Visible = false;
                this.viewTextBox.Visible = true;
            }
            else
            {
                this.richTextBox.Visible = true;
                this.viewTextBox.Visible = false;
            }
            this.viewTextBox.RenderModel(model, font);
        }

        public void DVScroll(object sender, int value, ScrollEventArgs e)
        {
            viewTextBox.DVScroll(sender, value, e);
        }

    }

    public delegate void ScrollEventPlasHandler(object sender,int value,ScrollEventArgs e);

    public class EditTextBox : TextBox
    {
        public EditTextBox()
        {
            this.Multiline = true;
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
        }

    }

    public class ViewTextBox : UserControl
    {
        private int padding = 0;
        private int minimum = 0;
        private int maximum = 100;
        private int maxLineCounts = 0;

        private int lineTop = 0;
        private int lineHeight = 17;

        private Font font;      
        private DiffPaneModel model;

        private int vScrollBarPos = 0;       
        private VScrollBar VScrollBar = null;

        private bool _multiline;
        public bool Multiline
        {
            get { return _multiline; }
            set { _multiline = value; }
        }

        private ScrollBars _scrollBars;
        public ScrollBars ScrollBars
        {
            get { return _scrollBars; }
            set { _scrollBars = value; }
        }

        internal NRichTextBoxControl ncontrol = null;
        
        public ViewTextBox()
        {
            DoubleBuffered = true;
            VScrollBar = new VScrollBar();            
            VScrollBar.Dock = DockStyle.Right;
            VScrollBar.Enabled = false;           
            VScrollBar.Scroll += new ScrollEventHandler(DoVScroller);
            this.Controls.Add(VScrollBar);
        }

        public void ResetScrollPos()
        {
            vScrollBarPos = 0;
            this.Invalidate();
        }

        public void ResetControlSize()
        {
            vScrollBarPos = 0;
            this.Invalidate();
        }

        public void RenderModel(DiffPaneModel model, Font font)
        {
            this.font = font;
            this.model = model;           
            this.Invalidate();           
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            Render(e.Graphics);            
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            ResetControlSize();
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            base.OnMouseWheel(e);
            if (!this.VScrollBar.Visible)
                return;
            int num1 = -e.Delta / lineHeight;
            if (this.VScrollBar.Value + num1 < this.VScrollBar.Minimum || this.VScrollBar.Value + num1 > this.VScrollBar.Maximum)
                return;
            int oldValue = this.VScrollBar.Value;
            int num2 = oldValue + num1;
            VScrollBar vscrollBar = this.VScrollBar;
            int num3 = vscrollBar.Value + num1;
            vscrollBar.Value = num3;
            this.DoVScroller((object)this, new ScrollEventArgs(ScrollEventType.SmallDecrement, oldValue, this.VScrollBar.Value));
        }

        protected void Render(Graphics g)
        {
            g.SmoothingMode = SmoothingMode.HighQuality;
            if (model != null)
            {
                lineTop = 0;
                maxLineCounts = 0;

                var lineIndex = 0;                 
                var lineForeColor = Color.Black;
                var lineBackColor = Color.White;               
                var lines = model.Lines;

                this.VScrollBar.Minimum = 0;

                var stringformat = new StringFormat();
                stringformat.LineAlignment = StringAlignment.Center;

                foreach (DiffPiece line in lines)
                {
                    var tempText = string.IsNullOrEmpty(line.Text) ? "测试文本" : line.Text;
                    var textsizef = TextRenderer.MeasureText(g, tempText, font);//new Size(this.Width, this.Height)
                    lineHeight = textsizef.Height + 0;

                    int lineCount = textsizef.Width % (this.Width - this.VScrollBar.Width) == 0 ? textsizef.Width / (this.Width - this.VScrollBar.Width) : textsizef.Width / (this.Width - this.VScrollBar.Width) + 1;
                    Rectangle lineRect = new Rectangle(padding, lineTop + padding + vScrollBarPos, (this.Width - this.VScrollBar.Width), lineCount * lineHeight);

                    switch (line.Type)
                    {
                        case ChangeType.Modified:
                            lineBackColor = Color.Red;
                            break;
                        case ChangeType.Deleted:
                            lineBackColor = SystemColors.ControlLight;
                            break;
                        case ChangeType.Inserted:
                            lineBackColor = Color.Green;
                            break;
                        case ChangeType.Imaginary:
                            lineBackColor = Color.Gold;
                            break;
                        default:
                            lineBackColor = Color.White;
                            break;
                    }

                    LineRenderer.FillBackground(g, lineBackColor, lineRect);
                    TextRenderer.DrawText(g, line.Text, font, lineRect, lineForeColor, Color.Transparent, TextFormatFlags.WordBreak | TextFormatFlags.TextBoxControl);

                    lineTop += lineRect.Height;

                    maxLineCounts += lineCount;

                    lineIndex++;
                }

                this.VScrollBar.Maximum = (maxLineCounts + 2) * lineHeight - this.Height;
                //this.VScrollBar.Maximum = (maxLineCounts - this.Height / lineHeight)*lineHeight;

                if (!this.VScrollBar.Enabled && this.VScrollBar.Maximum > 0)
                    this.VScrollBar.Enabled = true;
                else if (this.VScrollBar.Enabled && this.VScrollBar.Maximum <= 0)
                    this.VScrollBar.Enabled = false;

                if (this.VScrollBar.SmallChange != lineHeight)
                    this.VScrollBar.SmallChange = lineHeight;


            }
            g.SmoothingMode = SmoothingMode.Default;
        }

        private void DoVScroller(object sender, ScrollEventArgs e)
        {
            //vScrollBarPos += -lineHeight * (e.NewValue - e.OldValue);
            vScrollBarPos += -1 * (e.NewValue - e.OldValue);

            this.Invalidate();

            if (this.ncontrol != null && this.ncontrol.ScrollChanged != null)
            {               
                this.ncontrol.ScrollChanged(this.ncontrol.viewTextBox, VScrollBar.Value, e);
            }            
        }

        public void DVScroll(object sender, int value, ScrollEventArgs e)
        {
            vScrollBarPos += -1 * (e.NewValue - e.OldValue);
            if (value >= VScrollBar.Minimum && value <= VScrollBar.Maximum)
                VScrollBar.Value = value;
            this.Invalidate();
        }

        public class LineRenderer
        {
            public static void FillBackground(Graphics g, Color color, Rectangle rect)
            {
                g.FillRectangle(new SolidBrush(color), rect);
            }
        }

    }

    
}
